package com.wzb.mybatisplus.bitaction.electrumaction.btc01;

import org.bouncycastle.asn1.sec.SECNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.FixedPointCombMultiplier;

import java.math.BigInteger;

public class BitcoinPublicKeyFromPrivateKey {

    public static void main(String[] args) {

        // 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 G点
        System.out.println(new BigInteger("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",16));
        System.out.println(new BigInteger("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",16));
        System.out.println(new BigInteger("55066263022277343669578718895168534326250603453777594175500187360389116729240"));
        System.out.println(new BigInteger("32670510020758816978083085130507043184471273380659243275938904335757337482424"));
        System.out.println(new BigInteger("115792089237316195423570985008687907852837564279074904382605163141518161494337"));  //最大质素





        for(int i=1;i<1000;i++){
            // 获取 secp256k1 曲线参数
            X9ECParameters secp256k1 = SECNamedCurves.getByName("secp256k1");
            ECDomainParameters domainParams = new ECDomainParameters(
                    secp256k1.getCurve(),
                    secp256k1.getG(), // 生成点 G
                    secp256k1.getN(), // 曲线的阶 n
                    secp256k1.getH()
            );

            // 1. 定义私钥 k = 2
            BigInteger privateKey =  new BigInteger("26");
//            privateKey =privateKey.add(new BigInteger("115792089237316195423570985008687907853269984665640564039457584007908834671663"));
//            privateKey =privateKey.add(new BigInteger("100000000000000000000000000000000000000000000000000000000000000000000000000000"));
            System.out.println("私钥 k = " + privateKey);

            // 2. 计算公钥 K = k * G
            ECPoint publicKeyPoint = multiplyPoint(domainParams.getG(), privateKey, domainParams);
//            System.out.println(domainParams.getG());
            // 3. 获取公钥点的坐标
            ECPoint normalizedPoint = publicKeyPoint.normalize();
            BigInteger x = normalizedPoint.getAffineXCoord().toBigInteger();
            BigInteger y = normalizedPoint.getAffineYCoord().toBigInteger();

            System.out.println("\n公钥点坐标 K = (x, y):");
            System.out.println("x："+x +"     y："+y);
//            System.out.println("y："+y);
            System.out.println("Kx = " + x.toString(16).toUpperCase());
            System.out.println("Ky = " + y.toString(16).toUpperCase());

            // 4. 生成未压缩公钥 (04 + x + y)
            String uncompressedPublicKey = "04" +
                    toFixedSizeHex(x, 64) +
                    toFixedSizeHex(y, 64);
            System.out.println("\n未压缩公钥:");
            System.out.println(uncompressedPublicKey);

            // 5. 生成压缩公钥 (02/03 + x)
            // 判断 y 的奇偶性：y mod 2 == 0 表示偶数
            String compressedPrefix = y.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO) ? "02" : "03";
            String compressedPublicKey = compressedPrefix + toFixedSizeHex(x, 64);
            System.out.println("\n压缩公钥:");
            System.out.println(compressedPublicKey);

        }

        // 6. 验证结果（与已知的标准值比较）
//        System.out.println("\n验证结果:");
//        String expectedCompressed = "03C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5";
//        System.out.println("计算出的压缩公钥: " + compressedPublicKey);
//        System.out.println("预期的压缩公钥:   " + expectedCompressed);
//        System.out.println("是否匹配: " + compressedPublicKey.equals(expectedCompressed));
    }

    /**
     * 椭圆曲线点乘：计算 k * point
     */
    private static ECPoint multiplyPoint(ECPoint point, BigInteger k, ECDomainParameters domainParams) {
        // 使用固定点组合乘法器，这是最常用的点乘方法
        FixedPointCombMultiplier multiplier = new FixedPointCombMultiplier();
        return multiplier.multiply(point, k);
    }

    /**
     * 将 BigInteger 转换为固定长度的十六进制字符串
     */
    private static String toFixedSizeHex(BigInteger number, int size) {
        String hex = number.toString(16).toUpperCase();
        // 如果长度不足，前面补零
        while (hex.length() < size) {
            hex = "0" + hex;
        }
        return hex;
    }
}